import { Dep } from "./Dep";
let uid = 0
Dep.target = null

export class Watcher {
  /**
   * @param {*} target 组件的数据对象
   * @param {*} expression 目标属性
   * @param {*} callback 回调函数
   */
  constructor(target, expression, callback) {
    this.id = ++uid
    console.log('创建Watcher, id=', this.id);

    this.target = target
    
    this.getter = parsePath(expression) // 执行this.getter()就可以读取目标属性的内容，即：target.a.b.c的值
    this.callback = callback // 这个watcher在数据变化的时候要执行的回调函数：computed｜页面更新
    this.value = this.get() // 这个value就相当于，这个Watcher要观察的具体数据
  }
  // 获取target的具体数据，也就是会调用数据的getter方法  **
  // 在数据的getter中在自己的dep添加这个watcher        **
  get() {

    // 读取目标属性的过程，设置Dep.target
    Dep.target = this
    const obj = this.target
    let value 
    try {
      value = this.getter(obj)
    } finally {
      Dep.target = null
    }
    return value
  }
  update() {
    this.run()
  }
  run() {
    this.getAndInvoke(this.callback);
  }
  getAndInvoke(cb) {
    const value = this.get();
    if (value !== this.value || typeof value === 'object') {
      const oldValue = this.value;
      this.value = value;
      cb.call(this.target, value, oldValue);
    }
  }
}

/**
 * 将str用.分割成数组segments，然后循环数组，一层一层去读取数据，最后拿到的obj就是str中想要读的数据
 * @param {*} str
 * @returns
 */
function parsePath(str) {
  let segments = str.split(".");
  return function (obj) {
    for (let key of segments) {
      if (!obj) return;
      obj = obj[key];
    }
    return obj;
  };
}